﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Web;
using Lari.Configuration;
using Lari.Framework.Exceptions;
using Lari.Framework.Utility;
using Lari.Services.Data;
using Lari.Services.ViewModel;

namespace Lari.DataAccess
{
    public static class UserManagerDataAccess
    {
        private static string CurrentUser   
        { 
            get
            {
                if (HttpContext.Current != null && HttpContext.Current.User.Identity.IsAuthenticated)
                    return HttpContext.Current.User.Identity.Name;

                return null;
            }
        }


        private static DateTime CurrentDate { get { return DateTime.Now; } }
        
        
        public static List<AppModule> GetAllModules(LariDbContext db)
        {
            return db.AppModules.OrderBy(x => x.Caption).ToList();
        }

        public static List<Role> GetAllRoles(string search, LariDbContext db)
        {
            if (search.Trim() == "*")
                return db.Roles.ToList().OrderBy(s => s.Name).ToList();
            return db.Roles.Where(p => p.Name.Contains(search.Trim())).ToList().OrderBy(s => s.Name).ToList();
        }
        public static List<AppModule> GetAllModulesWithAccess(LariDbContext db)
        {
            return db.AppModules.Include("Accesses").ToList();
        }

        public static Role GetCompleteRole(int roleId, LariDbContext db)
        {
            return db.Roles.Include("RoleAccesses.Access.AppModule").FirstOrDefault(r => r.ID == roleId);
        }

        public static Role RoleOnly(int roleid, LariDbContext db)
        {
            return db.Roles.Find(roleid);
        }
        
        
        //public static int SaveRoleAccess(Role role, List<AppModule> moduleList, int? opid)
        //{
        //    //using (LariDbContext db = new LariDbContext(false))
        //    //{
        //    //    if (role.ID == default(int)) // insert role
        //    //    {
        //    //        role.CreatedBy = opid;
        //    //        role.CreatedOn = DateTime.Now;
        //    //        db.Entry(role).State = EntityState.Added;
        //    //    }
        //    //    else
        //    //    {
        //    //        role.UpdatedBy = opid;
        //    //        role.UpdatedOn = DateTime.Now;
        //    //        db.Entry(role).State = EntityState.Modified;
        //    //        // delete role command
        //    //        db.RoleCommands.Where(rc => rc.RoleId == role.ID).ToList().ForEach(rc =>
        //    //            {
        //    //                db.Entry(rc).State = EntityState.Deleted;
        //    //            });
        //    //        db.RoleAccesses.Where(ra => ra.RoleId == role.ID).ToList().ForEach(ra =>
        //    //            {
        //    //                db.Entry(ra).State = EntityState.Deleted;
        //    //            });
        //    //    }

        //    //    // construct role access 
        //    //    #region Construct role access and command
        //    //    moduleList.ForEach(mod =>
        //    //    {
        //    //        mod.Accesses.ToList().ForEach(acc0 =>
        //    //        {
        //    //            if (acc0.IsEnabled)
        //    //            {
        //    //                var ra0 = new RoleAccess() { RoleId = role.ID, AccessId = acc0.ID, IsEnabled = acc0.IsEnabled };
        //    //                db.Entry(ra0).State = EntityState.Added;

        //    //                #region Save command
        //    //                acc0.AppCommands.ToList().ForEach(cmd =>
        //    //                {
        //    //                    if (cmd.IsEnabled)
        //    //                    {
        //    //                        var command = new RoleCommand() { RoleId = role.ID, CommandId = cmd.ID, IsEnabled = true };
        //    //                        db.Entry(command).State = EntityState.Added;
        //    //                    }

        //    //                });
        //    //                #endregion

        //    //                acc0.Children.ToList().ForEach(acc1 =>
        //    //                    {
        //    //                        if (acc1.IsEnabled)
        //    //                        {
        //    //                            var ra1 = new RoleAccess() { RoleId = role.ID, AccessId = acc1.ID, IsEnabled = acc1.IsEnabled };
        //    //                            db.Entry(ra1).State = EntityState.Added;

        //    //                            #region save commands
        //    //                            acc1.AppCommands.ToList().ForEach(cmd =>
        //    //                                {
        //    //                                    if (cmd.IsEnabled)
        //    //                                    {
        //    //                                        var command = new RoleCommand() { RoleId = role.ID, CommandId = cmd.ID, IsEnabled = true };
        //    //                                        db.Entry(command).State = EntityState.Added;
        //    //                                    }

        //    //                                });
        //    //                            #endregion

        //    //                            #region Save access
        //    //                            acc1.Children.ToList().ForEach(acc2 =>
        //    //                                {
        //    //                                    if (acc2.IsEnabled)
        //    //                                    {
        //    //                                        var ra2 = new RoleAccess() { RoleId = role.ID, AccessId = acc2.ID, IsEnabled = acc2.IsEnabled };
        //    //                                        db.Entry(ra2).State = EntityState.Added;
        //    //                                        #region Save commands
        //    //                                        acc2.AppCommands.ToList().ForEach(cmd =>
        //    //                                        {
        //    //                                            if (cmd.IsEnabled)
        //    //                                            {
        //    //                                                var command = new RoleCommand() { RoleId = role.ID, CommandId = cmd.ID, IsEnabled = true };
        //    //                                                db.Entry(command).State = EntityState.Added;
        //    //                                            }

        //    //                                        });
        //    //                                        #endregion
        //    //                                    }

        //    //                                });
        //    //                            #endregion
        //    //                        }

        //    //                    });
        //    //            }


        //    //        });



        //    //    });
        //    //    #endregion

        //    //    db.SaveChanges();

        //    //}
        //    return role.ID;
        //}

        

//        private static void OpenConnection(LariDBContext db)
//        {
//            if (db != null && db.Connection.State == ConnectionState.Closed)
//                db.Connection.Open();
//        }
//        private static void RollbackTransaction(DbTransaction tx)
//        {
//            if (tx != null)
//                tx.Rollback();
//        }
//        public static Employee Authenticate(string userId, string password)
//        {
//            Employee user;
//            using (LariDBContext db = new LariDBContext())
//            {
//                user = db.Employees.Include("Role.RoleAccesses").Where(s => s.UserId == userId && s.Pwd == password).SingleOrDefault();

//            }
//            return user;
//        }
//        public static List<Facility> GetFacilitiesForuser(int userId)
//        {
//            List<Facility> s;
//            using (LariDBContext db = new LariDBContext())
//            {
//                var x = from f in db.Facilities
//                        join uf in db.UsersFacilities
//                            on f.ID equals uf.FacilityID
//                        where uf.UserID == userId
//                        select f;
//                s = x.ToList();


//            }
//            return s;
//        }
//        public static void SetDefaultFacility(int userId, int facilityId)
//        {
//            DbTransaction tx = default(DbTransaction);
//            try
//            {
//                using (LariDBContext db = new LariDBContext())
//                {
//                    OpenConnection(db);
//                    using (tx = db.Connection.BeginTransaction())
//                    {

//                        var user = db.Employees.Single(s => s.ID == userId);
//                        if (user != null)
//                        {
//                            user.DefaultFacilityId = facilityId;
//                            db.SaveChanges();
//                        }
//                        tx.Commit();
//                    }
//                }
//            }
//            catch
//            {
//                RollbackTransaction(tx);
//                throw;
//            }
//        }
//        public static void ChangePassword(int userId, string newPassword, string oldPassword)
//        {
//            DbTransaction tx = default(DbTransaction);
//            try
//            {
//                using (LariDBContext db = new LariDBContext())
//                {
//                    OpenConnection(db);
//                    using (tx = db.Connection.BeginTransaction())
//                    {
//                        var user = db.Employees.Where(s => s.ID == userId).Single();
//                        if (user.Pwd != oldPassword)
//                            throw new LariException(ExceptionCode.UM.OLD_PASSWORD_MISMATCH, false);

//                        user.Pwd = newPassword;
//                        user.TxnUser = userId;
//                        user.Txndate = DateTime.Now;
//                        db.Employees.ApplyChanges(user);
//                        db.SaveChanges();
//                        tx.Commit();
//                    }
//                }
//            }
//            catch
//            {
//                RollbackTransaction(tx);
//                throw;
//            }
//        }
//        public static List<Employee> SearchUsers(string userIdRLastNameHint)
//        {
//            List<Employee> retValue;
//            using (LariDBContext db = new LariDBContext())
//            {
//                var x = from u in db.Employees.Include("Role")
//                        where u.UserId.StartsWith(userIdRLastNameHint)
//                            || u.LastName.StartsWith(userIdRLastNameHint)
//                        select u;

//                retValue = x.ToList();

//            }
//            return retValue;
//        }
//        public static void ResetPassword(int userID, string newPwd,int opid)
//        {
//            DbTransaction tx = default(DbTransaction);
//            try
//            {
//                using (LariDBContext db = new LariDBContext())
//                {
//                    OpenConnection(db);
//                    using (tx = db.Connection.BeginTransaction())
//                    {
//                        var user = db.Employees.Single(s => s.ID == userID);
//                        if (user != null)
//                        {
//                            user.Pwd = newPwd;
//                            user.Txndate = DateTime.Now;
//                            user.TxnUser = opid;

//                            db.SaveChanges();
//                            tx.Commit();
//                        }
//                    }
//                }

//            }
//            catch
//            {
//                RollbackTransaction(tx);
//                throw;
//            }
//        }
//        public static bool IsUserExists(string userID)
//        {
//            bool retVal;
//            using (LariDBContext db = new LariDBContext())
//            {
//                retVal = db.Employees.Any(s => s.UserId.ToUpper() == userID.ToUpper());

//            }
//            return retVal;
//        }
//        public static Employee GetUser(int userID)
//        {
//            Employee retVal;
//            using (LariDBContext db = new LariDBContext())
//            {
//                retVal = db.Employees.Include("UsersFacilities").Where(s => s.ID == userID).Single();

//            }
//            return retVal;
//        }
//        public static int Save(Employee user, int? opid)
//        {
//            DbTransaction tx = default(DbTransaction);

//            try
//            {
//                using (LariDBContext db = new LariDBContext())
//                {
//                    OpenConnection(db);
//                    using (tx = db.Connection.BeginTransaction())
//                    {
//                        if (user.ID == default(int))
//                        {

//                            if (db.Employees.Any(s => s.UserId.ToUpper() == user.UserId.ToUpper()))
//                            {
//                                throw new LariException(ExceptionCode.UM.USER_FORM_UAER_ALREADY_EXIST, false);
//                            }
//                            user.TxnCrDate = DateTime.Now;
//                            user.TxnCrUser = opid;

//                            db.Employees.AddObject(user);
//                            db.SaveChanges();


//                        }
//                        else
//                        {
//                            user.Txndate = DateTime.Now;
//                            user.TxnUser = opid;
//                            var ufList = user.UsersFacilities.ToList();
//                            user.UsersFacilities.Clear();

//                            db.UsersFacilities.Where(s => s.UserID == user.ID).ToList().ForEach(a =>
//                            {
//                                db.UsersFacilities.DeleteObject(a);
//                            });
//                            db.SaveChanges();
//                            db.Employees.ApplyChanges(user);
//                            db.SaveChanges();
//                            ufList.ForEach(s => db.UsersFacilities.AddObject(s));
//                            db.SaveChanges();

//                        }


//                        tx.Commit();
//                    }
//                }
//            }
//            catch
//            {
//                RollbackTransaction(tx);
//                throw;

//            }
//            return user.ID;
//        }


//        public static List<Employee> GetAllEmployees()
//        {
//            List<Employee> user;
//            using (LariDBContext db = new LariDBContext())
//            {
//                user = db.Employees.Include("Role.RoleAccesses").ToList();

//            }
//            return user;
//        }

//        //public static void CheckForLicence()
//        //{
             
//        //    //todo:do it only for fist time by checking registration transaction table.
//        //    DbTransaction tx = default(DbTransaction);

//        //     try
//        //     {
//        //         using (LariDBContext db = new LariDBContext())
//        //         {
//        //             OpenConnection(db);
//        //             using (tx = db.Connection.BeginTransaction())
//        //             {
//        //                 if (db.TSystems.Count() == 0)
//        //                 {
//        //                     TSystem trail = new TSystem();
//        //                     trail.TSF = Encryption.Encrypt(((int)TrailStatusEnum.Running).ToString()) ;
//        //                     trail.TSK = Encryption.Encrypt(Guid.NewGuid().ToString());
//        //                     trail.TSV = Encryption.Encrypt(Guid.NewGuid().ToString());
//        //                     trail.TSD = Encryption.Encrypt(DateTime.Now.ToString("dd/MM/yyyy"));
//        //                     trail.TSP = Encryption.Encrypt("60");

//        //                     db.TSystems.AddObject(trail);
//        //                     db.SaveChanges();
//        //                     tx.Commit();

//        //                 }
//        //             }
//        //         }
//        //     }
//        //     catch
//        //     {
//        //         RollbackTransaction(tx);
//        //     }

//        //}

//        public static List<TSystem> GetAllTSystems()
//        {
//            List<TSystem> ret;
//            using (LariDBContext db = new LariDBContext())
//            {
//                ret = db.TSystems.ToList();

//            }
//            return ret;
//        }

//        //public static void TSystemUpgradeLicense(string license, bool fullupgrade)
//        //{
//        //    DbTransaction tx = default(DbTransaction);
//        //    try
//        //    {
//        //        using (LariDBContext db = new LariDBContext())
//        //        {
//        //            OpenConnection(db);
//        //            using (tx = db.Connection.BeginTransaction())
//        //            {
//        //                TSystem lic = db.TSystems.Single();
//        //                if (fullupgrade)
//        //                {

//        //                    string temLic = Encryption.Encrypt(Encryption.Decrypt(lic.TSK) + Encryption.Decrypt(lic.TSV));
//        //                    if (license != temLic)
//        //                    {
//        //                        throw new LariException("License is invalid.", false);
//        //                    }
//        //                    else
//        //                    {
//        //                        lic.TSL = license;
//        //                        lic.TSF = Encryption.Encrypt(((int)TrailStatusEnum.Licenced).ToString());
//        //                        db.TSystems.ApplyChanges(lic);
//        //                        db.SaveChanges();

//        //                    }

//        //                }
//        //                else
//        //                {
//        //                    int days = int.Parse(Encryption.Decrypt(lic.TSP));
//        //                    if (days >= 90)
//        //                    {
//        //                        throw new LariException("You have already consumed maximum trail period(90 days).", false);
//        //                    }
//        //                    else
//        //                    {
//        //                        lic.TSP = Encryption.Encrypt((days + 30).ToString());
//        //                        db.TSystems.ApplyChanges(lic);
//        //                        db.SaveChanges();
                                
//        //                    }


//        //                }
//        //                tx.Commit();
                        
//        //            }
//        //        }
//        //    }
//        //    catch
//        //    {
//        //        RollbackTransaction(tx);
//        //        throw;

//        //    }
//        //}

        public static void SaveRole(RoleModel role, LariDbContext db)
        {
            if (role.Id == default(int)) 
            {
                if (db.Roles.Any(r => r.Name == role.Name))
                    throw new LariException(MessageCode.Generic.DuplicateCodeName);

                db.Entry(new Role{CreatedBy = CurrentUser,CreatedOn = DateTime.Now,Name = role.Name}).State = EntityState.Added;
                
                role.Modules.ForEach(m => m.Accesses.ForEach(ac =>
                {
                    var roleAccess = new RoleAccess { AccessId = ac.Id, IsEnabled = ac.HasAccess, RoleId = role.Id };

                    db.Entry(roleAccess).State = EntityState.Added;

                }));

                db.SaveChanges();
            }
            else
            {
                if (db.Roles.Any(r => r.ID != role.Id && r.Name == role.Name))
                    throw new LariException(MessageCode.Generic.DuplicateCodeName);

                var dbRole = db.Roles.FirstOrDefault(r => r.ID == role.Id);
                if (dbRole != null)
                {
                    dbRole.UpdatedBy = CurrentUser;
                    dbRole.UpdatedOn = DateTime.Now;
                    dbRole.Name = role.Name;
                    db.Entry(dbRole).State = EntityState.Modified;

                    db.RoleAccesses.Where(ra => ra.RoleId == role.Id).ToList().ForEach(ra =>
                    {
                        db.Entry(ra).State = EntityState.Deleted;
                    });

                    role.Modules.ForEach(m => m.Accesses.ForEach(ac=>
                            {
                                var roleAccess = new RoleAccess
                                                 {AccessId = ac.Id, IsEnabled = ac.HasAccess, RoleId = role.Id};

                                    db.Entry(roleAccess).State = EntityState.Added;
                                
                            }));

                    db.SaveChanges();

                }
                
                
            }
        }

        public static bool ValidateUser(string userid, string currentPassword, LariDbContext db)
        {
           return db.Users.Any(u => u.UserId == userid && u.Password == currentPassword);
        }

        public static void ChangePassword(string userId, string newPassword, LariDbContext db)
        {
            var user = db.Users.FirstOrDefault(u => u.UserId == userId);
            if (user!=null)
            {
                user.Password = Encryption.Encrypt(newPassword);
                user.TxnUser = CurrentUser;
                user.Txndate = DateTime.Now;
                db.SaveChanges();
            }
        }

        public static void SaveHintQuestionAnswer(UserProfileModel model, LariDbContext db)
        {
            UserProfile profile = db.UserProfiles.FirstOrDefault(uf => uf.UserId == model.UserId);
            if (profile == null)
            {
                profile = new UserProfile{CreatedBy = CurrentUser,CreatedOn = DateTime.Now};
                db.Entry(profile).State = EntityState.Added;
            }
            else
            {
                profile.UpdatedBy = CurrentUser;
                profile.UpdatedOn = DateTime.Now;
                db.Entry(profile).State = EntityState.Modified;
            }
            profile.UserId = model.UserId;
            profile.HintQuestion1 = model.HintQuestion1;
            profile.HintQuestion2 = model.HintQuestion2;
            profile.HintQuestion3 = model.HintQuestion3;

            profile.HintAnswer1 = model.HintAnswer1;
            profile.HintAnswer2 = model.HintAnswer2;
            profile.HintAnswer3 = model.HintAnswer3;

            db.SaveChanges();
        }

        public static int SaveEmployee(EmployeeModel view, LariDbContext db)
        {
            var model = view.ConvertToEntityModel();

            if (model.DOB!=null)
            {
                model.IsDOBCulculated = false;
            }
            else
            {
                model.IsDOBCulculated = true;
                if (model.Age != null) model.DOB = DateTime.Now.AddYears(-1*model.Age.Value);
            }
            model.HomeStateOther = string.IsNullOrWhiteSpace(model.HomeStateCode) ? model.HomeStateOther : string.Empty;
            model.WorkStateOther = string.IsNullOrWhiteSpace(model.WorkStateCode) ? model.WorkStateOther : string.Empty;

            model.Active = true;
            if (model.ID == 0)
            {
                model.TxnCrUser = CurrentUser;
                model.TxnCrDate = DateTime.Now;

                db.Entry(model).State = EntityState.Added;
                db.SaveChanges();
                return model.ID;  
            }
            
            var dbModel = db.Employees.Find(model.ID);
                
            if (dbModel != null)
            {
                dbModel.ModeltoModelMapping(model);
                dbModel.TxnUser = CurrentUser;
                dbModel.Txndate = DateTime.Now;

                db.Entry(dbModel).State = EntityState.Modified;
                db.SaveChanges();
                return dbModel.ID;  
            }
            return 0;
        }

        public static Employee Employee(int id, LariDbContext db)
        {
            return db.Employees.Include("User").Include("EmployeeLicenses").Include("EmployeeQualifications").FirstOrDefault(e => e.ID == id);
        }

        public static void SaveUser(int empId, string userid, string password,int roleId, LariDbContext db)
        {
            if (db.Users.Any(u => u.UserId == userid))
            {
                throw new LariException(MessageCode.User.UserIdAlreadytaken);
            }
            var user = new User
                           {
                               EmployeeID = empId,
                               UserId = userid,
                               Password = Encryption.Encrypt(password),
                               RoleID = roleId,
                               TxnCrUser = CurrentUser,
                               TxnCrDate = DateTime.Now
                           };
            db.Entry(user).State = EntityState.Added;
            db.SaveChanges();
        }

        public static void ChangeEnployeeActivStatus(int empId,bool status, LariDbContext db)
        {
            var employee = db.Employees.Find(empId);
            if (employee != null)
            {
                employee.Active = status;
                employee.TxnUser = CurrentUser;
                employee.Txndate = DateTime.Now;
                db.Entry(employee).State = EntityState.Modified;
                db.SaveChanges();
            }
        }

        public static UserMgrGlanceModel GetAdminGlance(LariDbContext db)
        {
            var model = new UserMgrGlanceModel
                            {
                                ActiveEmployees = db.Employees.Count(e => e.Active),
                                InActiveEmployees = db.Employees.Count(e => !e.Active),
                                ActiveUsers = db.Users.Count(u => u.Employee.Active),
                                InactiveUsers = db.Users.Count(u => !u.Employee.Active),
                                NoMappedEmployees = db.Employees.Count() - db.Users.Count(),
                                NoHintQuestionEmployees = db.Users.Count() - db.UserProfiles.Count()
                            };
            return model;
        }

        public static bool IsCurrentUserHasHintQuestion(LariDbContext db)
        {
            return db.UserProfiles.Any(up => up.UserId == CurrentUser);
        }

        public static List<EmployeesUsersView> SearchEmployeesUser(LariDbContext db,string searchParam,int currentPage, ref int totalPageCount)
        {
            if (searchParam.Trim().ToLower() == "*")
            {

                var temp = db.EmployeesUsersViews.OrderBy(ue=> ue.Id);
               
                totalPageCount = (int)Math.Ceiling((double)temp.Count() / ApplicationConfig.RowPerPage);

                var result = temp.Skip((currentPage - 1) * ApplicationConfig.RowPerPage)
                .Take(ApplicationConfig.RowPerPage)               
                .ToList();
                return result;
            }
            else
            {
                var temp = db.EmployeesUsersViews.Where(ue => ue.SearchString.Contains(searchParam)).OrderBy(ue=> ue.Id);
                totalPageCount = (int)Math.Ceiling((double)temp.Count() / ApplicationConfig.RowPerPage);

                var result = temp.Skip((currentPage - 1) * ApplicationConfig.RowPerPage)
                .Take(ApplicationConfig.RowPerPage)
                .ToList();
                return result;
            }
        }

        public static void  ChangeRole(LariDbContext db, int empId, int roleId)
        {
            var user = db.Users.Find(empId);
            if (user != null)
            {
                user.RoleID = roleId;
                user.TxnUser = CurrentUser;
                user.Txndate = CurrentDate;
                db.Entry(user).State = EntityState.Modified;
                db.SaveChanges();
            }
        }

        public static List<Specialization> SepecializationForDepartment(LariDbContext db, int departmentId)
        {
            return db.Specializations.Where(s => s.DepartmentID == departmentId).ToList();
        }

        public static List<ConsultantSpecialization> SpecializationForConsultant(LariDbContext db, int empId)
        {
            return db.ConsultantSpecializations.Include("Specialization").Where(s => s.EmpId == empId).ToList();
        }

        public static void AddConsultantSpecialization(LariDbContext db, int empId, List<int> specializationList)
        {
           
            specializationList.ForEach(s=>
                                           {
                                               var consultantSpec = new ConsultantSpecialization
                                                                        {
                                                                            EmpId = empId,
                                                                            SpecialisationId = s,
                                                                            Txndate = CurrentDate,
                                                                            TxnUser = CurrentUser
                                                                        };
                                               db.Entry(consultantSpec).State = EntityState.Added;

                                           });

            db.SaveChanges();

        }

        public static void RemoveConsultantSpecialization(LariDbContext db, int empId, List<int> specializationList)
        {
            specializationList.ForEach(spcid=>
                                           {
                                               var consSpec =
                                                   db.ConsultantSpecializations.FirstOrDefault(cs => cs.EmpId == empId && cs.SpecialisationId == spcid);
                                                       

                                               if (consSpec != null)
                                               {
                                                   db.Entry(consSpec).State = EntityState.Deleted;
                                               }
                                           });
            db.SaveChanges();
        }
    }
}
